#pragma once
#ifndef _UTILS_H
#define _UTILS_H

#include <utility>
#include <ostream>
#include <stack>
#include <vector>
#include <string>
#include <ctime>
#include <sstream>

#include <boost/serialization/is_bitwise_serializable.hpp>
#include <boost/serialization/access.hpp>
#include <boost/mpi.hpp>

#include "board.h"

extern const bool DEBUG;

namespace utils
{

	typedef std::pair<unsigned, unsigned> coords_t;

	std::ostream& operator<<(std::ostream& os, const coords_t &c)
	{
		os << "[" << c.first << "," << c.second << "]";
		return os;
	}

	template<class T>
	std::ostream& printVector(std::ostream& os, const std::vector<T> &v) {
		os << '[';
		for (unsigned i = 0; i < v.size(); i++) {
			os << v[i] << ':';
		}
		os << "]\n";
		return os;
	}

	//x,y - souradnice, n - velikost CTVERCOVE matice
	inline unsigned coordsToIndex(const unsigned x, const unsigned y, const unsigned n)
	{
		return y * n + x;
	}

	inline unsigned coordsToIndex(const coords_t& _coor, const unsigned n)
	{
		return coordsToIndex(_coor.first, _coor.second, n);
	}

	//i - index v 1rozmernem poli, n-velikost ctvercove matice
	coords_t indexToCoords(unsigned i, unsigned n)
	{
		return coords_t(i%n,i/n);
	}

	/////////////////////////////////////////////////////////////
	//Metoda pro vypis vrcholu zasobniku do streamu
	template <class T>
	void dumpStack(const std::stack<T> &st, std::ostream &os, const unsigned cntr)
	{
		os << cntr << ":\n";
		os << st.top().boardLayout << "\n";
		os << st.top() << "\n";
	}

	//////////////////////////////////////////////////////////////////////////
	// Funkce pro zalogovani nejake zpravy, prip. objektu, co ma definovan
	// vypis do streamu.
	template <class T>
	void log(const T& msg, std::ostream& os = std::cout)
	{
		if (DEBUG)
		{
			static boost::mpi::communicator world;
			os << "[" << world.rank() << "] " << msg << std::endl;
		}
	}

	template <class T>
	void print(const T& msg, std::ostream& os = std::cout)
	{
		static boost::mpi::communicator world;
		os << "[" << world.rank() << "] " << msg << std::endl;
	}

	template <class T>
	void masterPrint(const T& msg, std::ostream& os = std::cout)
	{
		static boost::mpi::communicator world;
		if (world.rank() == 0)
		{
			os << "[" << world.rank() << "] " << msg << std::endl;
		}
	}
	
	//////////////////////////////////////////////////////////////////////////
	//
	template<class T>
	std::string toString(const T& t)
	{
		std::stringstream s;
		s << t;
		return s.str();
	}
	template<class T1, class T2>
	std::string toString(const T1& t1, const T2& t2)
	{
		std::stringstream s;
		s << t1 << t2;
		return s.str();
	}
	template<class T1, class T2, class T3>
	std::string toString(const T1& t1, const T2& t2, const T3& t3)
	{
		std::stringstream s;
		s << t1 << t2 << t3;
		return s.str();
	}
	template<class T1, class T2, class T3, class T4>
	std::string toString(const T1& t1, const T2& t2, const T3& t3, const T4& t4)
	{
		std::stringstream s;
		s << t1 << t2 << t3 << t4;
		return s.str();
	}

}	//End of namespace utils


#endif // _UTILS_H
